package br.ufrj.dcc.ad.args;

import java.util.HashMap;
import java.util.Map;

public class ParameterBuilder {
	private String args;
	private final String delimiter = "\\t+|\\s+|=";
	private final String newLine = System.getProperty("line.separator");
	
	private static HashMap<String, SimulationParameters> canonicalParameters, aliasParameters;
	
	public ParameterBuilder(String[] args) {
		StringBuilder sb = new StringBuilder();
		for(String s : args) {
			sb.append(" ").append(s);
		}
		this.args = sb.toString();
	}
	
	public String toString() {
		return args;
	}
	
	public String getParametersList(String prefix) {
		StringBuilder sb = new StringBuilder();
		SimulationParameters[] params = SimulationParameters.values();
		int i = 0, size = params.length;
		
		if(prefix == null) prefix = "";
		
		for(i = 0; i < size; ++i) {
			SimulationParameters param = params[i];
			
			sb	.append(prefix).append("-").append(param.getAlias());
			
			if(param.getType() != null) {
				sb.append(" ").append(param.getType().getSimpleName());
			}
			sb	.append(", ")
				.append("--").append(param.getCanonicalName());
			if(param.getType() != null) {
				sb.append("=").append(param.getType().getSimpleName());
			}
			
			if(param.getSample() != null) {
				sb.append(" exemplo: ").append(param.getSample());
			}
			
			if((i+1) < size) {
				sb.append(newLine);
			}
		}
		return sb.toString();
	}
	
	public Map<SimulationParameters, String> build() throws IllegalArgumentException {
		HashMap<SimulationParameters, String> arguments = new HashMap<SimulationParameters, String>();
		String token, subToken = null;
		SimulationParameters param = null;
		int size = 0;
		
		String[] tokens = this.args.split(delimiter);
		size = tokens.length;
		
		for(int i = 0; i < size; ++i) {
			token = tokens[i];
			if(token.trim().isEmpty()) continue;
			
			if(token.charAt(0) != '-') {
				throw new IllegalArgumentException("Argumento " + token + " nao esperado!");
			}
			if(token.charAt(1) != '-') {
				subToken = token.substring(1);
				param = aliasParameters.get(subToken);
			} else {
				subToken = token.substring(2);
				param = canonicalParameters.get(subToken);
			}
			
			if(param == null) {
				throw new IllegalArgumentException("Argumento " + subToken + " nao esperado!");
			}
			
			if(param == SimulationParameters.HELP) {
				arguments.clear();
				arguments.put(param, "");
				return arguments;
			}
			
			while(i < size) {
				if((i+1) == size) {
					throw new IllegalArgumentException("Argumento esperado!");
				}
				token = tokens[++i];
				if(token.trim().isEmpty()) continue;
				else break;
			}
			
			if(token.charAt(0) == '-') {
				throw new IllegalArgumentException("Valor \"" + token + "\" para " + param.toString() + " invalido!");
			} else if(! evaluate(param, token)) {
				throw new IllegalArgumentException("Valor \"" + token + "\" para " + param.toString() + " invalido!");
			}
			
			arguments.put(param, token);
		}
		return arguments;
	}
	
	private boolean evaluate(SimulationParameters param, String value) {
		boolean result = false;
		try {
			if(String.class.equals(param.getType())) {
				return true;
			}
			if(param.getType().asSubclass(Number.class) != null) {
				// Se der exception nesse caso, não deveria...
				result = false;
				Double.valueOf(value);
				return true;
			}
			return false;
		} catch(Exception e) {
			return result;
		}
	}
	
	static {
		canonicalParameters = new HashMap<String, SimulationParameters>();
		aliasParameters = new HashMap<String, SimulationParameters>();
		for(SimulationParameters s : SimulationParameters.values()) {
			aliasParameters.put(s.getAlias(), s);
			canonicalParameters.put(s.getCanonicalName(), s);
		}
	}
}
